﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

using System.Net;
using System.Net.Sockets;


using RetroNET.Network;

namespace RetroNET
{
	public partial class RetroNETCore
	{
		public void cbReceiveDataFromClient(IAsyncResult result)
		{
			try
			{
				RNClient client = (RNClient)result.AsyncState;
				int numBytes = client.sockIn.EndReceive(result);
				
				if (numBytes == 0)
				{
					// Socket disconnected for some reason. Let's clean up and GTFO
					Console.WriteLine("Client " + client.sockIn.RemoteEndPoint + " disconnected, cleaning up...");
					ClientCleanup(client);
					return;
				}

				string recvData = Encoding.ASCII.GetString(client.inputbuffer, 0, numBytes);
				client.recvBufferClient.Append(recvData); // Tack this on to the end of the buffer
				client.inputbuffer = new byte[1024];

				//Console.WriteLine("[" + client.sockIn.RemoteEndPoint + "]: " + recvData);

				// Now try parsing what we have...
				PreprocessClientCommandBuffer(client);

				// Start listening again...
				if (client.sockIn.Connected) client.ListenToClient(this);
				else ClientCleanup(client);


			}
			catch (Exception ex)
			{
				Console.WriteLine("[cbReceiveDataFromClient] ERROR: " + ex);

				ClientCleanup((RNClient)result.AsyncState);
			}
		}

		public void cbSendClientDataToDestination(IAsyncResult result)
		{
			try
			{
				RNClient client = (RNClient)result.AsyncState;

				int numBytes = client.sockOut.EndReceive(result);
				if (numBytes == 0)
				{
					// Socket disconnected for some reason. Let's clean up and GTFO
					Console.WriteLine("Client " + client.sockOut.RemoteEndPoint + " disconnected, cleaning up...");
					ClientCleanup(client);
					return;
				}

				string recvData = Encoding.ASCII.GetString(client.inputbuffer, 0, numBytes);
				client.recvBufferClient.Append(recvData); // Tack this on to the end of the buffer

				Console.WriteLine("[" + client.sockIn.RemoteEndPoint + "->" + client.sockOut.RemoteEndPoint + "]: " + recvData);

				// Now try parsing what we have...
				PreprocessClientCommandBuffer(client);

				// Start listening again...
				if (client.sockIn.Connected) client.ListenToClient(this);
				else ClientCleanup(client);

			}
			catch (Exception ex)
			{
				Console.WriteLine("[cbReceiveDataFromClient] ERROR: " + ex);

				ClientCleanup((RNClient)result.AsyncState);
			}
		}

		private void PreprocessClientCommandBuffer(RNClient client)
		{
			if (!client.recvBufferClient.ToString().Contains("\r\n")) return; // If we don't have a CRLF in the string, abort (we haven't received a complete command)


			string[] tok = client.recvBufferClient.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

			foreach (string cmd in tok)
			{
				if (cmd.Length > 0)
				{
					//Console.WriteLine("[" + client.sockIn.RemoteEndPoint + "] Recieved command: \"" + cmd + "\"");
				}

				client.recvBufferClient.Remove(0, cmd.Length + 2); // Cut out the command we just tried to parse + CRLF

				ParseClientCommand(client, cmd);
			}


		}

		void cbSentDataToClient(IAsyncResult result)
		{
			try
			{

				RNClient client = (RNClient)result.AsyncState;

				int sentBytes = client.sockIn.EndSend(result);

				//Console.WriteLine("*** Sent " + sentBytes + " bytes to " + client.sockIn.RemoteEndPoint.ToString());

			}
			catch (Exception ex)
			{
				Console.WriteLine("[cbSentDataToClient] ERROR: " + ex);

				ClientCleanup((RNClient)result.AsyncState);
			}
		}
	}
}